<!DOCTYPE html>
<html>
    <head>
        <title>Zwave Network</title>
        <meta charset="utf-8">
		<link rel="stylesheet" href="css/bootstrap.css">
        <link href="css/bootstrap-responsive.css" rel="stylesheet" media="screen">
        <link type="text/css" rel="stylesheet" href="css/ui-darkness/jquery-ui.min.css" />
		<link type="text/css" rel="stylesheet" href="css/demo_table_jui.css" />
		<link type="text/css" rel="stylesheet" href="css/jquery.uix.multiselect.css" />
        <link type="text/css" rel="stylesheet" href="css/style.css" />
        <link type="text/css" rel="stylesheet" href="css/colpick.css" />
		<script src="js/jquery-3.3.1.min.js"></script>
		<script src="js/i18next-1.8.0.min.js"></script>
        <script src="js/bootstrap.min.js"></script>
		<script src="js/bootbox.min.js"></script>
        <script src="js/jquery-ui.min.js"></script>

        <!-- Highcharts is not needed here but domoticz.js depends on it -->
		<script charset="utf-8" src="js/highcharts/highcharts.js"></script>
		<script charset="utf-8" src="js/domoticz.js"></script>

		<script src="js/d3.min.js"></script>
		<script charset="utf-8" src="js/data-tables/jquery.dataTables.min.js"></script>

		<script>

		function getParameter(paramName) {
			var searchString = window.location.search.substring(1),i, val, params = searchString.split('&');
			for (i=0;i<params.length;i++) {
				val = params[i].split('=');
				if (val[0] == paramName) {
					return unescape(val[1]);
				}
			}
			return null;
		}


        function getNodeId(node){
            return (
                addLeadingZeros(node.nodeID, 3)
                + ' (0x' + addLeadingZeros(node.nodeID.toString(16), 2) + ')'
            );
        }

		function getNodeName(node){
		    return node ? node.nodeName : '';
		}

		function getGroupName(group){
			return group ? group.groupName : '';
		}

		function removeNodeFromGroup(event) {
			var node = event.data.node;
			var group = event.data.group;
			var removeNode = event.data.removeNode;
			var removeNodeId = event.data.removeNodeId;
			var hwid=getParameter('hwid');
			bootbox.confirm($.t(
					'Are you sure you want to remove this node?<br>'
					+ 'Node: ' + getNodeName(removeNode)
					+ ' (' + removeNodeId
					+ ')<br>From group: ' + getGroupName(group)
					+ '<br>On node ' + getNodeName(node)), function(result) {
				if (result==true) {
					$.ajax({
						 url: "json.htm?type=command&param=zwaveremovegroupnode&idx=" + hwid + "&node=" + node.nodeID + "&group=" + group.id + "&removenode=" + removeNodeId,
						 async: false,
						 dataType: 'json',
						 success: function(data) {
							bootbox.alert($.t('Groups updated!'));
							$("#grouptable").empty();
							drawGroupTable();
						 }
					});
				}
			});
		}
		function addNodeToGroup(event) {
		    var node = event.data.node;
		    var group = event.data.group;
			var hwid=getParameter('hwid');
			bootbox.dialog({
			  message: $.t("Please enter the node to add to this group:")+"<input type='text' id='add_node' data-toggle='tooltip' title='NodeId or NodeId.Instance'></input><br>" + group.groupName,
			  title: 'Add node to ' + getNodeName(node),
			  buttons: {
				main: {
				  label: $.t("Save"),
				  className: "btn-primary",
				  callback: function() {
					var addnode = $("#add_node").val();
					$.ajax({
						url: "json.htm?type=command&param=zwaveaddgroupnode&idx=" + hwid + "&node=" + node.nodeID + "&group=" + group.id + "&addnode=" + addnode,
						async: false,
						dataType: 'json',
						success: redrawGroupTable()
					});
				  }
				},
				 nothanks: {
					 label: $.t("Cancel"),
					 className: "btn-cancel",
					 callback: function() {
					 }
				 }
			  }
			});
		}

		function redrawGroupTable()  {
			bootbox.alert($.t('Groups updated. It can take a while before changes are visible.'));
			$("#grouptable").empty();
			drawGroupTable();
		}

		function drawGroupTable()
		{
			var hwid = getParameter("hwid");
			$.ajax({
				url: "json.htm?type=command&param=zwavegroupinfo&idx=" + hwid,
				async: false,
				dataType: 'json',
				success: function(data) {
					if (typeof data != 'undefined') {
						if (data.status=="OK") {
							if (typeof data.result != 'undefined') {
								grouptable = $('#grouptable');
								var maxgroups = data.result.MaxNoOfGroups;
								var thead = $('<thead></thead>');
								var trow = $('<tr></tr>');

								$('<th></th>').text($.t("Node")).appendTo(trow);
								$('<th></th>').text($.t("Name")).appendTo(trow);
								for (var i = 0; i < maxgroups; i++) {
									$('<th></th>').text($.t("Group") + " " + (i + 1)).appendTo(trow);
								}
								trow.appendTo(thead);
								thead.appendTo(grouptable);
								tbody = $('<tbody></tbody>');

								var jsonnodes = data.result.nodes;
								var nodes = {};
								var i = jsonnodes.length;
								while (i--) {
                                    var node = jsonnodes[i];
									nodes[node.nodeID] = node;
								}
								$.each(jsonnodes, function(i, node) {
									var groupsDone = 0;
									noderow = $('<tr>');
									$('<td>').text(getNodeId(node)).appendTo(noderow);
									$('<td>').text(node.nodeName).appendTo(noderow);
									noGroups = node.groupCount;
									if (noGroups > 0) {
										groupnodes = node.groups;
										$.each(groupnodes, function(g, group) {
											td = $('<td>').data('toggle', 'tooltip').attr('title', getGroupName(group));

											function createButton(text){
												var button = $('<span>');
												button.text(text);
												button.addClass('label label-info lcursor');
												return button;
											}

											$.each(group.nodes.split(','), function(){
												if (this!="") {
													var button = createButton(this);
													var removeNodeId = this * 1;
													var removeNode = nodes[Math.round(removeNodeId)];
													button.click({node: node, group: group, removeNode: removeNode, removeNodeId: this}, removeNodeFromGroup);
													button.attr('title', getNodeName(removeNode) + ' on ' + getGroupName(group));
													button.appendTo(td);
												}
											});
											var button = createButton('+');
											button.click({node: node, group: group}, addNodeToGroup);
											button.appendTo(td);
											td.appendTo(noderow);
											groupsDone++;
										});
									}
									if (groupsDone<maxgroups) {
										var missing = maxgroups-noGroups;
										for (var i = 0; i < missing; i++) {
											$('<td></td>').text(' ').appendTo(noderow);
											groupsDone++;
										}
									}
									noderow.appendTo(tbody);
								});
								tbody.appendTo(grouptable);
								tfoot = $('<tfoot></tfoot>');
								tfoot.appendTo(grouptable);
								$('#grouptable').dataTable({
								  "sDom": '<"H"lfrC>t<"F"ip>',
								  "oTableTools": {
									"sRowSelect": "single",
								  },
								  "aaSorting": [[ 0, "desc" ]],
								  "bSortClasses": false,
								  "bProcessing": true,
								  "bStateSave": true,
								  "bJQueryUI": true,
								  "bDestroy": true,
								  "bLengthChange": false,
								  "aLengthMenu": [[5,10], [5,10]],
								  "iDisplayLength": 10,
								  "sPaginationType": "full_numbers",
								  paging: false,
								  language: $.DataTableLanguage
								});
							}
						}
					}
				}
			});
		}

		function drawChord() {

			var width = window.innerWidth*0.39;
			var height = window.innerHeight*0.8;
			innerRadius = Math.min(width, height) * .40,
			outerRadius = innerRadius * 1.1;
			var nodeslist=[];
			var nodearray=[];
			var posdict = {};
			var matrix=[];

			var hwid = getParameter("hwid");

			$.ajax({
				url: "json.htm?type=command&param=zwavenetworkinfo&idx=" + hwid,
				async: false,
				dataType: 'json',
				success: function(data) {
					if (typeof data != 'undefined') {
						if (data.status=="OK") {
							if (typeof data.result != 'undefined') {

								jsonnodes = data.result.mesh;
								var pos = 0;
								$.each(jsonnodes, function(i, item) {
									nodeslist.push(item.nodeID);
									posdict[item.nodeID] = pos;
									pos++;
								});
								var rowlength = pos;
								$.each(jsonnodes, function(i, item) {
									var seesNodes = item.seesNodes;
									var row=[];
									var filleddict = {};
									$.each(seesNodes.split(','), function(){
										if (this!="") {
											filleddict[posdict[this]]=1;
										}
									});
									filleddict[posdict[item.nodeID]]=1;
									for (var i=0;i<rowlength;i++)
									{
										if (filleddict[i]==1) {
											row.push(1);
										}
										else {
											row.push(0);
										}
									}
									matrix.push(row);
								});
							}
						}
					}
				}
			});

			var svg = d3.select("#networkchart").append("svg")
				.attr("width", width)
				.attr("height", height)
				.attr("style","align: center; diplay:block; margin: 0 auto; ")
			  .append("g")
				.attr("transform", "translate("+width/2+","+height/2+")");

			var chord = d3.layout.chord()
				.matrix(matrix)
				.padding(0.05)
				.sortSubgroups(d3.descending);

			var fill = d3.scale.category10();

			var g = svg.selectAll("g.group")
				.data(chord.groups)
			  .enter().append("svg:g")
				.attr("class", "group");

			var arc = d3.svg.arc()
				.innerRadius(innerRadius)
				.outerRadius(outerRadius);

			g.append("path")
				.attr("d", arc)
				.style("fill", function(d) { return fill(d.index); })
				.style("stroke", function(d) { return fill(d.index); })
				.attr("id", function(d, i) { return "group-" + d.index });;

			 g.append("text")
				  .each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; })
				  .attr("dy", ".35em")
				  .attr("transform", function(d) {
					return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
						+ "translate(" + (innerRadius + 26) + ")"
						+ (d.angle > Math.PI ? "rotate(180)" : "");
				  })
				  .style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
				  .text(function(d) { return nodeslist[d.index]; });

			function groupTicks(d) {
			  var k = (d.endAngle - d.startAngle) / 1; //append some width for unconnected ones
			  return d3.range(0, d.value, 1).map(function(v, i) {
				return {
				  angle: v * k + d.startAngle,
				  label: ""
				};
			  });
			}

			var ticks = g.selectAll("g")
				.data(groupTicks)
			  .enter().append("g")
				.attr("transform", function(d) {
				  return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
					  + "translate(" + outerRadius + ",0)";
				});

			ticks.append("text")
				.attr("x", 8)
				.attr("dy", ".35em")
				.attr("transform", function(d) {
					return d.angle > Math.PI ?
						"rotate(180)translate(-16)" : null;
				})
				.style("text-anchor", function(d) {
					return d.angle > Math.PI ? "end" : null;
				})
				.text(function(d) { return d.label; });

			function chordColor(d) {
				return fill(d.source.value > d.target.value ?
					d.source.index : d.target.index);
			}

			svg.append("g")
				.attr("class", "chord")
			  .selectAll("path")
				.data(chord.chords)
			  .enter().append("path")
				.attr("d", d3.svg.chord().radius(innerRadius))
				.style("fill", chordColor)
				.style("opacity", 1);

			function fade(opacity) {
				return function(g, i) {
					svg.selectAll(".chord path")
					   .filter(function(d) {
							return d.source.index != i &&
								   d.target.index != i;
						})
					   .transition()
					   .style("opacity", opacity);
				};
			}
			g.on("mouseover", fade(0.1))
			 .on("mouseout", fade(1));
		}

		function drawInfo() {
			$.ajax({
 				 url: "json.htm?type=command&param=getlanguage",
				 async: false,
				 dataType: 'json',
				 success: function(data) {
					if (typeof data.language != 'undefined') {
						SetLanguage(data.language);
					}
					else {
						SetLanguage('en');
					}
				 },
				 error: function(){
				 }
			});
			drawChord();
			drawGroupTable();
		}
		</script>


		<style>
			body {
				background: none;
			}
			span.label.label-info {
				margin:3px;
			}
            .chord path {
              fill-opacity: .5;
              stroke-width: .6px;
            }
            .node path { fill-opacity: 0.6; }
            text.node { font-size: 13px; }
			div.outer {
				position: relative;
				clear: both;
			}
			div.left {
				width: 40%;
				position: relative;
				float: left;
			}
			div.right {
				width: 60%;
				position: relative;
				float: right;
				overflow: auto;
			}

			</style>
    </head>
    <body onload="drawInfo()">
		<div class="outer">
			<div class="left" ><div align="center" id="networkchart"></div></div>
			<div class="right"><table class="display" id="grouptable"></div>
		</div>

	</body>
    </html>
